import { MysqlConn, toWhere } from "./base";
import { Util } from "../lib/Util";

class Unit<T>{
    private mydb: MysqlConn
    private table: string
    private findKey: { [x: string]: any }
    private loaded = false
    private _data: any = {}
    private changeList: string[] = []
    private _bindAutoSave: Function
    constructor(db: MysqlConn, table: string, findKey: { [x: string]: any }) {
        this._bindAutoSave = this.autoSave.bind(this);
        this.mydb = db
        this.table = table;
        this.findKey = findKey;
    }

    get empty() {
        return Object.keys(this._data).length == 0
    }

    // 增加筛选能力，0和1不能同时存在
    async load(filter?: { [x: string]: 0 | 1 }, sort?: { [x: string]: -1 | 1 }) {
        try {
            let show: string[] = []
            filter = filter || {}
            let keys = Object.keys(filter)
            if (keys.length > 0) {
                if (filter[keys[0]] == 0) {
                    // 这里是屏蔽模式
                    let listInfo = this.mydb.tableFields[this.table];
                    if (listInfo) for (let key in listInfo) if (filter[key] == undefined) show.push(key)
                }
                else {
                    show = keys;
                }
            }

            let qStr = `select ${show.length == 0 ? '*' : show.join(',')} from  ${this.table} `;
            if (Object.keys(this.findKey).length > 0) {
                qStr += `where ${toWhere(this.findKey)}`
            }

            if (sort) {
                let str = " order by "
                for (let key in sort) {
                    str += ` ${key} ${(sort[key] == -1) ? "Desc" : ""}`
                }

                qStr += str;
            }

            let list = await this.mydb.query(qStr + " limit 1")
            if (list.length > 0) {
                this._data = list[0]
            }
            else {
                this._data = {}
            }
            this.loaded = true
        }
        catch (e) {
            throw e
        }

        if (Object.keys(this.findKey).length == 0) {
            // 如果找到了一个，那么就换掉查询条件，方便后续修改保存等操作
            // 找一下是否有主键，有的话使用主键
            let info = this.mydb.tableFields[this.table];
            let mainKeys: any = {}
            for (let key in info) {
                if (info[key].Key && this._data[key] != undefined) {
                    mainKeys[key] = this._data[key];
                }
            }

            if (Object.keys(mainKeys).length != 0) {
                this.findKey = mainKeys;
            }
            else {
                this.findKey = Util.copy(this.data)
            }
        }

        return this;
    }

    get data() {
        return this._data as T
    }

    insert(info: { [x: string]: any }) {
        this._data = info;
        return this.mydb.insert(this.table, info)
    }

    // 设置数据到缓存 数据异常的时候不异常，返回失败
    set(key: string, value: string | number | Buffer | Date) {
        // 设置数据
        try {
            value = this.mydb.checkFileds(this.table, key, value)
            // mysql严格上没有二级三级存储，所以我们暂时不支持到那么复杂的处理
            this._data[key] = value;
            this.flag(key);
            this.checkUpdate()
            return true;
        }
        catch (e) {
            return false;
        }
    }

    // 保存的时候对于异常的数据直接error
    setSafe(key: string, value: string | number | Buffer | Date) {
        // 设置数据
        value = this.mydb.checkFileds(this.table, key, value)
        // mysql严格上没有二级三级存储，所以我们暂时不支持到那么复杂的处理
        this._data[key] = value;
        this.flag(key);
        this.checkUpdate()
        return true;
    }

    // 设置某个字段强制同步数据库
    flag(key: string) {
        if (this.changeList.indexOf(key) < 0) this.changeList.push(key)
        this.checkUpdate()
        return this
    }

    // 立即删除
    delete() {
        return this.mydb.deleteOnce(this.table, this.findKey)
    }

    private _autoCheck = 0;
    force_save() {
        if (this._autoCheck) {
            clearTimeout(this._autoCheck)
        }
        return this.autoSave()
    }

    private checkUpdate() {
        if (this._autoCheck) return
        this._autoCheck = setTimeout(this._bindAutoSave, 1000);
    }

    private async autoSave() {
        if (this.changeList.length == 0) return true;
        let infos: string[] = []
        let ff = this.mydb.tableFields[this.table];
        for (let i = 0; i < this.changeList.length; i++) {
            let key = this.changeList[i]
            let value = this._data[key]

            infos.push(`\`${key}\` = ${this.mydb.toSqlStr(ff[key].Type.type, value)}`);
        }

        this.changeList = []
        this._autoCheck = 0;
        let sql = `update ${this.table} set ${infos.join(",")} where ${toWhere(this.findKey)} limit 1`
        await this.mydb.query(sql)
        // 这里再刷新一下findkey
        for (let key in this.findKey) {
            this.findKey[key] = this._data[key]
        }

        return true;
    }
}

export function GetUnit<T>(db: MysqlConn, table: string, findKey: { [x: string]: any }) {
    return new Unit<T>(db, table, findKey)
}